<?php
namespace app\pays;

/**
 * 所有支付接口，包含微信、支付宝和第三方 2018-3-7 温宗敏
 */
class PayCommon extends CustomCommon
{
	protected $WechatnotifyUrl='http://wx.shpqkj.com/pays/index.php/WebPay/WechatPayNotice';//微信支付成功通知接口

	protected $UnionnotifyUrl='http://wx.shpqkj.com/pays/index.php/WebPay/UnionPayNotice';//微信支付成功通知接口

	protected $unionUrl='https://qr.chinaums.com/netpay-portal/webpay/pay.do?';//银联下单支付接口



/*********************************************************************银联支付******************************************************************/
	/**
     * @根据ASCII编码升序排列，并返回签名数据
	 * @return array 返回的数据
     */
	public function UnionWeiXinMd5($array,$money)
	{
		$signkey=$array['key'];
		if(strlen($signkey)==0)
		{
			$this->errormsg("银联支付秘钥不匹配");
		}
		//定义2种时间类型
		$longdatetime=date('YmdHis', time());
		$datetime=date('Y-m-d H:i:s', time());
		if(strlen($array['notifyUrl'])==0){
			$array['notifyUrl']=$this->UnionnotifyUrl;
		}
		foreach ($array as $key => $value) {
			//查询是否有空值，如果有空值返回错误
			if(strlen($value)==0){
				$this->errormsg("参数‘".$key.'’不能为空值');
			}
		}
		$attachedData='{"p":"'.$_SESSION['phone'].'","c": "'.$_SESSION['cardno'].'","o":"'.$_SESSION['oldmoney'].
			'","n":"'.$_SESSION['money'].'","type":"'.$_SESSION['rechargetype'].'","pid":"'.$_SESSION['pid'].'"}';
		//自定义通用函数
		$general=array(
			"attachedData"=>$attachedData,
			"merOrderId" =>$array['msgSrcId'].$array['id'].$longdatetime,//订单号
			"requestTimestamp" => $datetime,//请求时间
			"totalAmount" => $money*100,//乘以100是为了把分转换成元(单位的转换)
			);
		//合并数组
		$arrayParam=array_merge($general,$array);
		//删除不需要的键值
		unset($arrayParam['id']);
		unset($arrayParam['key']);  
		unset($arrayParam['isuse']); 
		unset($arrayParam['msgSrcId']);
		//ASCII排序
		ksort($arrayParam);
		//签名字符串
		$strParam="";//$this->ToUrlParams($arrayParam).$signkey;
		foreach ($arrayParam as $key => $value) {
			$strParam=$strParam.$key."=".$value."&";
		}
		//签名字符串
		$signParam=substr($strParam,0,strlen($strParam)-1).$signkey;
		//签名
		$sign=strtoupper(md5($signParam));
		//关键参数用urlencode转换一下
		$strParam=str_replace($datetime,urlencode($datetime),$strParam);
		$strParam=str_replace($attachedData,urlencode($attachedData),$strParam);
		$strParam=str_replace($this->UnionnotifyUrl,urlencode($this->UnionnotifyUrl),$strParam);
		return array('code'=>200,'result'=>$this->unionUrl.$strParam.'sign='.$sign,'type'=>'union');
	}

	/**
     * @根据ASCII编码升序排列，并返回签名数据
	 * @return array 返回的数据
     */
	public function UnionTradeMd5($array,$money)
	{
		$this->errormsg("暂未开通银联支付宝支付");
	}

	/**
     * @根据ASCII编码升序排列，并返回签名数据
	 * @return array 返回的数据
     */
	public function UnionQmfMd5($array,$money)
	{
		$this->errormsg("暂未开通银联全民付");
	}

	/**
     * @根据ASCII编码升序排列，并返回签名数据
	 * @return array 返回的数据
     */
	public function UnionWebPayMd5($array,$money)
	{
		$this->errormsg("暂未开通银联无卡支付");
	}



/*********************************************************微信H5支付**********************************************************************************/
	

	/**
     * @根据ASCII编码升序排列，并返回签名数据
	 * @return array 返回的数据
     */
	public function WechatMd5($array,$money,$url,$openid)
	{
		$signkey=$array['key'];
		if(strlen($signkey)==0)
		{
			$this->errormsg("微信支付秘钥不匹配");
		}
		//定义2种时间类型
		$longdatetime=date('YmdHis', time());
		$datetime=date('Y-m-d H:i:s', time());
		if(strlen($array['notify_url'])==0){
			$array['notify_url']=$this->WechatnotifyUrl;
		}
		foreach ($array as $key => $value) {
			//查询是否有空值，如果有空值返回错误
			if(strlen($value)==0){
				$this->errormsg("参数‘".$key.'’不能为空值');
			}
		}
		//$sql = "select appid,mch_id,body,notify_url,`key`,wap_url,wap_name,id,isuse from wechatpay where `pid` like :keyword";
		//$wap_name=isset($array['wap_name']) ? $array['wap_name'] : '充值';
		//$wap_url=isset($array['wap_url']) ? $array['wap_url'] : 'wx.shpqkj.com';\
		//'scene_info'=>'{"h5_info": {"type":"Wap","wap_url": "'.$wap_url.'","wap_name": "'.$wap_name.'"}}',

		//自定义通用函数
		$general=array(
			'attach'=>'{"p":"'.$_SESSION['phone'].'","c": "'.$_SESSION['cardno'].'","o":"'.$_SESSION['oldmoney'].
			'","n":"'.$_SESSION['money'].'","type":"'.$_SESSION['rechargetype'].'","pid":"'.$_SESSION['pid'].'"}',
			'openid'=>$openid,
			'trade_type'=>'JSAPI',
			'spbill_create_ip'=>$_SESSION['userip'],
			'nonce_str'=>'weixin',
			"out_trade_no" =>$array['id'].$longdatetime,//订单号
			"total_fee" => $money*100,//乘以100是为了把分转换成元(单位的转换)
			);
//$this->errormsg(strlen($general['attach']));
		//合并数组
		$arrayParam=array_merge($general,$array);
		$arrayParam['spbill_create_ip']=$_SESSION['userip'];
		//删除不需要的键值
		unset($arrayParam['id']);
		unset($arrayParam['key']);  
		unset($arrayParam['isuse']); 
		unset($arrayParam['wap_url']);
		unset($arrayParam['wap_name']);
		unset($arrayParam['appsecret']);
		unset($arrayParam['sub_appid']);
		unset($arrayParam['sub_mch_id']);
		//ASCII排序
		ksort($arrayParam);
		$strParam="";
		foreach ($arrayParam as $key => $value) {
			$strParam=$strParam.$key."=".$value."&";
		}
		//签名字符串
		$signParam=$strParam.'key='.$signkey;
		//签名
		$sign=strtoupper(md5($signParam));
		$arrayParam['sign']=$sign;
		$xml= $this->ToXml($arrayParam);

		/******解析参数重签名支付参数*****/
		$resultXml= $this->postXmlCurl($xml, $url, false, 120);
		$resultArray=$this->toArray($resultXml);
		if (!isset($resultArray['prepay_id'])){
			$this->errormsg("获取订单详情扩展字符串错误".json_encode($resultArray));
		}
		$resData = array(  
                'appId' => strval($arrayParam['appid']),  
                'nonceStr' => strval($arrayParam['nonce_str']),  
                'package' => 'prepay_id='.$resultArray['prepay_id'],  
                'signType' => 'MD5',  
                'timeStamp' => date('Y-m-d H:i:s', time())//,
				//"total_fee" => $money*100//乘以100是为了把分转换成元(单位的转换)
         );
		//ASCII排序
		ksort($resData);
		$strParam="";
		foreach ($resData as $key => $value) {
			$strParam=$strParam.$key."=".$value."&";
		}
		//签名字符串
		$signParam=$strParam.'key='.$signkey;
		//签名
        $resData['paySign'] = strtoupper(md5($signParam));  
		//exit(json_encode($signParam.'&sign='.$resData['paySign']));
		
		return json_encode(array('code'=>200,'result'=>$resData,'type'=>'wechat'));
	}


	/**
     * @根据ASCII编码升序排列，并返回签名数据
	 * @return array 返回的数据
     */
	public function SubWechatMd5($array,$money,$url,$openid)
	{
		//获取鹏企支付秘钥
		$signkey=$array['key'];
		/*//获取子商户公众账号appid
		$subappid="wxbf2e4b96cd5b24b3";
		//获取子商户号
		$submid="1487579462";*/
		if(strlen($signkey)==0)
		{
			$this->errormsg("微信支付秘钥不匹配");
		}
		//定义2种时间类型
		$longdatetime=date('YmdHis', time());
		$datetime=date('Y-m-d H:i:s', time());
		if(strlen($array['notify_url'])==0){
			$array['notify_url']=$this->WechatnotifyUrl;
		}
		foreach ($array as $key => $value) {
			//查询是否有空值，如果有空值返回错误
			if(strlen($value)==0){
				$this->errormsg("参数‘".$key.'’不能为空值');
			}
		}

		//自定义通用函数
		$general=array(
			//'sub_appid'=>$subappid,
			//'sub_mch_id'=>$submid,
			//'fee_type'=>'CNY',
			'attach'=>'{"p":"'.$_SESSION['phone'].'","c": "'.$_SESSION['cardno'].'","o":"'.$_SESSION['oldmoney'].
			'","n":"'.$_SESSION['money'].'","type":"'.$_SESSION['rechargetype'].'","pid":"'.$_SESSION['pid'].'"}',
			'openid'=>$openid,
			'trade_type'=>'JSAPI',
			'spbill_create_ip'=>$_SESSION['userip'],
			'nonce_str'=>'weixin',
			"out_trade_no" =>$array['id'].$longdatetime,//订单号
			"total_fee" => $money*100,//乘以100是为了把分转换成元(单位的转换)
			);
		//合并数组
		$arrayParam=array_merge($general,$array);
		$arrayParam['spbill_create_ip']=$_SESSION['userip'];
		//删除不需要的键值
		unset($arrayParam['id']);
		unset($arrayParam['key']);  
		unset($arrayParam['isuse']); 
		unset($arrayParam['wap_url']);
		unset($arrayParam['wap_name']);
		unset($arrayParam['appsecret']);
		//ASCII排序
		ksort($arrayParam);
		$strParam="";
		foreach ($arrayParam as $key => $value) {
			$strParam=$strParam.$key."=".$value."&";
		}
		//签名字符串
		$signParam=$strParam.'key='.$signkey;

		$this->paylogs($signParam);
		//签名
		$sign=strtoupper(md5($signParam));
		$arrayParam['sign']=$sign;
		$xml= $this->ToXml($arrayParam);

		/******解析参数重签名支付参数*****/
		$resultXml= $this->postXmlCurl($xml, $url, false, 120);
		
		$resultArray=$this->toArray($resultXml);
		if (!isset($resultArray['prepay_id'])){
			$this->paylogs("获取订单详情扩展字符串错误".json_encode($resultArray).$xml);
			$this->errormsg($resultArray['return_msg']);
		}
		$resData = array(  
                'appId' => strval($arrayParam['appid']),  
                'nonceStr' => strval($arrayParam['nonce_str']),  
                'package' => 'prepay_id='.$resultArray['prepay_id'],  
                'signType' => 'MD5',  
                'timeStamp' => date('Y-m-d H:i:s', time())//,
         );
		//ASCII排序
		ksort($resData);
		$strParam="";
		foreach ($resData as $key => $value) {
			$strParam=$strParam.$key."=".$value."&";
		}
		//签名字符串
		$signParam=$strParam.'key='.$signkey;
		//签名
        $resData['paySign'] = strtoupper(md5($signParam));  
		
		return json_encode(array('code'=>200,'result'=>$resData,'type'=>'wechat'));
	}
	

	/**
     * @微信扫码支付
	 * @return array 返回的数据
     */
	public function WechatScanCodePay($array,$money,$url,$auth_code)
	{
		$signkey=$array['key'];
		if(strlen($signkey)==0)
		{
			$this->errormsg("微信支付秘钥不匹配");
		}

		/*//获取子商户公众账号appid
		$subappid="wxbf2e4b96cd5b24b3";
		//获取子商户号
		$submid="1487579462";*/
		//定义2种时间类型
		$longdatetime=date('YmdHis', time());
		$datetime=date('Y-m-d H:i:s', time());
		if(strlen($array['notify_url'])==0){
			$array['notify_url']=$this->WechatnotifyUrl;
		}
		foreach ($array as $key => $value) {
			//查询是否有空值，如果有空值返回错误
			if(strlen($value)==0){
				$this->errormsg("参数‘".$key.'’不能为空值');
			}
		}
		//自定义通用函数
		$general=array(
			//'sub_appid'=>'wxbf2e4b96cd5b24b3',//$array['subappid'],
			//'sub_mch_id'=>'1487579462',//$array['submid'],
			'auth_code'=>$auth_code,
			'spbill_create_ip'=>$_SESSION['userip'],
			'nonce_str'=>'weixin',
			"out_trade_no" =>$array['id'].$longdatetime,//订单号
			"total_fee" => $money*100,//乘以100是为了把分转换成元(单位的转换)，
			"time_start"=> date("YmdHis", time()),
			"time_expire"=>date("YmdHis",strtotime("+70 seconds"))
			);
			
		//exit(json_encode($general));
		//合并数组
		$arrayParam=array_merge($general,$array);
		
		$arrayParam['spbill_create_ip']=$_SESSION['userip'];
		//删除不需要的键值
		unset($arrayParam['id']);
		unset($arrayParam['key']);  
		unset($arrayParam['isuse']); 
		unset($arrayParam['wap_url']);
		unset($arrayParam['wap_name']);
		unset($arrayParam['appsecret']);
		unset($arrayParam['notify_url']);

		//exit(json_encode($arrayParam));
		//ASCII排序
		ksort($arrayParam);
		$strParam="";
		foreach ($arrayParam as $key => $value) {
			$strParam=$strParam.$key."=".$value."&";
		}
		//签名字符串
		$signParam=$strParam.'key='.$signkey;
		//签名
		$sign=strtoupper(md5($signParam));
		$arrayParam['sign']=$sign;
		$xml= $this->ToXml($arrayParam);
		/******解析参数重签名支付参数*****/
		$resultXml= $this->postXmlCurl($xml, $url, false, 120);
		$resultArray=$this->toArray($resultXml);
		//exit(json_encode($resultArray));
		if ($resultArray['return_code']=='FAIL'){
			$this->errormsg($resultArray['return_msg']);
		}
		//$this->paylogs('beijing');
		if($resultArray['result_code']=='FAIL'){
			//这些标识支付结果未知
			$resultCode=array('SYSTEMERROR','BANKERROR','USERPAYING');//AUTH_CODE_INVALID
			//$this->paylogs($resultArray['err_code_des']);
			if(in_array($resultArray['err_code'], $resultCode)){
				//$this->paylogs($resultArray['err_code_des']);
				//$this->errormsg('['.$resultArray['err_code_des'].']支付结果未知，可调用查询接口查询结果');
				//可能需要用户输入密码
				//如果用户30秒还没支付，则返回支付失败
				$isPay=false;
				for ($x=0; $x<=70; $x++) {
					$this->paylogs('等待客户支付'.$x);
					if($this->QueryWechatScanPay($arrayParam,$signkey)){
						$this->paylogs('查询支付成功，现在开始返回结果'.$x);
						//如果订餐查询支付成功则直接返回支付成功
						$isPay=true;
						$x=100;
						continue;
					}
					//暂停 70 秒
					sleep(1);
				}
				if($isPay==false){
					exit(json_encode(array('code'=>-1, 'message'=>$resultArray['err_code_des'],'outtradeno'=>$arrayParam['out_trade_no'])));
				}
			}
			else{
				$this->paylogs($resultArray['err_code_des']);
				$this->errormsg('['.$resultArray['err_code_des'].']支付失败，请重新生成二维码');
			}
		}
		$this->paylogs(json_encode($arrayParam).'成功支付');
		return json_encode(array('code'=>200, 'message'=>'成功支付','outtradeno'=>$arrayParam['out_trade_no']));
		//return json_encode(array('code'=>200,'result'=>'成功支付','type'=>'wechatscan'));
	}

	function QueryWechatScanPay($array,$signkey)
	{
		if(isset($array['sub_appid']))
		{
			//自定义通用函数
			$arrayParam=array(
			'sub_appid'=>$array['sub_appid'],
			'sub_mch_id'=>$array['sub_mch_id'],
			'appid'=>$array['appid'],
			'mch_id'=>$array['mch_id'],
			'nonce_str'=>$array['nonce_str'],
			"out_trade_no" =>$array['out_trade_no'],
			);
		}
		else
		{
			//自定义通用函数
			$arrayParam=array(
			'appid'=>$array['appid'],
			'mch_id'=>$array['mch_id'],
			'nonce_str'=>$array['nonce_str'],
			"out_trade_no" =>$array['out_trade_no'],
			);
		}
		
		//ASCII排序
		ksort($arrayParam);
		$strParam="";
		foreach ($arrayParam as $key => $value) {
			$strParam=$strParam.$key."=".$value."&";
		}
		//签名字符串
		$signParam=$strParam.'key='.$signkey;
		//签名
		$sign=strtoupper(md5($signParam));
		$arrayParam['sign']=$sign;
		$xml= $this->ToXml($arrayParam);
		/******解析参数重签名支付参数*****/
		$resultXml= $this->postXmlCurl($xml, 'https://api.mch.weixin.qq.com/pay/orderquery', false, 120);
		$resultArray=$this->toArray($resultXml);
		if ($resultArray['return_code']=='SUCCESS'&&$resultArray['trade_state']=='SUCCESS'){
			$this->paylogs("查询支付成功");
			$this->paylogs($resultXml);
			return true;
		}
		else if($resultArray['return_code']=='FAIL'){
			$this->paylogs($resultArray['return_msg'].$resultArray['trade_state_desc']);
		}
		else
		{
			$this->paylogs($resultXml);
		}
		return false;
	}

	function SendTemplMsg($token,$data)
	{
		$url='https://api.weixin.qq.com/cgi-bin/message/template/send?access_token='.$token;
		return $this->RequestUrl($url,'post',$data);
	}

	function postXmlCurl($xml, $url, $useCert = false, $second)
    {
        $ch = curl_init();

        //设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);

        curl_setopt($ch,CURLOPT_URL, $url);
        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
        curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);//严格校验
        //设置header
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        //要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        if($useCert == true){
            //设置证书
            //使用证书：cert 与 key 分别属于两个.pem文件
            curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
            curl_setopt($ch,CURLOPT_SSLCERT, WxPayConfig::SSLCERT_PATH);
            curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
            curl_setopt($ch,CURLOPT_SSLKEY, WxPayConfig::SSLKEY_PATH);
        }
        //post提交方式
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        //运行curl
        $data = curl_exec($ch);
        //返回结果
        if($data){
            curl_close($ch);
            return $data;
        } else {
            $error = curl_errno($ch);
            curl_close($ch);
			$this->errormsg('curl出错，错误码:'.$error);
        }
    }

	/**
	 * 
	 * 通过跳转获取用户的openid，跳转流程如下：
	 * 1、设置自己需要调回的url及其其他参数，跳转到微信服务器https://open.weixin.qq.com/connect/oauth2/authorize
	 * 2、微信服务处理完成之后会跳转回用户redirect_uri地址，此时会带上一些参数，如：code
	 * 
	 * @return 用户的openid
	 */
	public function GetOpenid($appid,$appsecret,$snsapi_base="snsapi_base")
	{
		//通过code获得openid
		if (!isset($_GET['code'])){
			//触发微信返回code码
			$baseUrl = urlencode('http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);//.$_SERVER['QUERY_STRING']
			$url = $this->CreateOauthUrlForCode($appid,$baseUrl,$snsapi_base);
			Header("Location: $url");
			exit();
		} else {
			//获取code码，以获取openid
		    $code = $_GET['code'];
			$data = $this->getOpenidFromMp($appid,$appsecret,$code);
			return $data;
		}
	}

	public function GetWechatUserInfo($access_token,$openid)
	{
		$url="https://api.weixin.qq.com/sns/userinfo?access_token=$access_token&openid=$openid&lang=zh_CN";

		//初始化curl
		$ch = curl_init();
		//设置超时
		curl_setopt($ch, CURLOPT_TIMEOUT, 120);
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,FALSE);
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,FALSE);
		curl_setopt($ch, CURLOPT_HEADER, FALSE);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
		//运行curl，结果以jason形式返回
		$res = curl_exec($ch);
		curl_close($ch);
		//取出openid
		$data = json_decode($res,true);
		if(isset($data['errcode'])){
			$this->errormsg($data['errmsg']);
		}
		return $data;
	}
	

	/**
	 * 
	 * 构造获取code的url连接
	 * @param string $redirectUrl 微信服务器回跳的url，需要url编码
	 * 
	 * @return 返回构造好的url
	 */
	private function CreateOauthUrlForCode($appid,$redirectUrl,$snsapi_base="snsapi_base")
	{
		$urlObj["appid"] = "$appid";
		$urlObj["redirect_uri"] = "$redirectUrl";
		$urlObj["response_type"] = "code";
		$urlObj["scope"] = "$snsapi_base";
		$urlObj["state"] = "STATE"."#wechat_redirect";
		$bizString = $this->ToUrlParams($urlObj);
		return "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString;
	}

	//获取token
    public function GetToken($appid,$appsecret){
        $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='.$appid.'&secret='.$appsecret;
        $res = $this->RequestUrl($url,'get');
        return $res['access_token'];
    }

	/**
	 * 
	 * 通过code从工作平台获取openid机器access_token
	 * @param string $code 微信跳转回来带上的code
	 * 
	 * @return openid
	 */
	public function GetOpenidFromMp($appid,$appsecret,$code)
	{
		$url = $this->CreateOauthUrlForOpenid($appid,$appsecret,$code);
		//初始化curl
		$ch = curl_init();
		//设置超时
		curl_setopt($ch, CURLOPT_TIMEOUT, 120);
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,FALSE);
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,FALSE);
		curl_setopt($ch, CURLOPT_HEADER, FALSE);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
		//if(WxPayConfig::CURL_PROXY_HOST != "0.0.0.0" 
		//	&& WxPayConfig::CURL_PROXY_PORT != 0){
		//	curl_setopt($ch,CURLOPT_PROXY, WxPayConfig::CURL_PROXY_HOST);
		//	curl_setopt($ch,CURLOPT_PROXYPORT, WxPayConfig::CURL_PROXY_PORT);
		//}
		//运行curl，结果以jason形式返回
		$res = curl_exec($ch);
		curl_close($ch);
		//取出openid
		$data = json_decode($res,true);
		if(isset($data['errcode'])){
			$this->errormsg($data['errmsg']);
		}
		//$this->data = $data;
		//$openid = $data['openid'];
		return $data;
	}
	/**
	 * 
	 * 构造获取open和access_toke的url地址
	 * @param string $code，微信跳转带回的code
	 * 
	 * @return 请求的url
	 */
	function CreateOauthUrlForOpenid($appid,$appsecret,$code)
	{
		$urlObj["appid"] = "$appid";
		$urlObj["secret"] = "$appsecret";
		$urlObj["code"] = $code;
		$urlObj["grant_type"] = "authorization_code";
		$bizString = $this->ToUrlParams($urlObj);
		return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
	}

}